
import 'package:first_flutter_project/main/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import '../AfterLayoutRoute.dart';
import '../Gesture/GestureDetectorConflictTest.dart';
import '../Gesture/GestureDetectorHitTest.dart';
import '../Gesture/NotificationInterruptTest.dart';

///基本的动画用法
class MyCustomHeroAnimatorUseingRoute extends StatefulWidget {
  @override
  _MyCustomHeroAnimatorUseingState createState() =>
      _MyCustomHeroAnimatorUseingState();
}

//需要继承TickerProvider，如果有多个AnimationController，则应该使用TickerProviderStateMixin。
class _MyCustomHeroAnimatorUseingState
    extends State<MyCustomHeroAnimatorUseingRoute>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;
  late Tween<double> tween;

  initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );

    //弹性用法速度
    final CurvedAnimation bounceIn =
        CurvedAnimation(parent: controller, curve: Curves.bounceIn);

    //匀速
    //图片宽高从0变到300
    tween = Tween(begin: 0.0, end: 300.0);
    animation = tween.animate(bounceIn)
      ..addListener(() {
        setState(() => {});
      });

    ///addListener()函数调用了setState()，所以每次动画生成一个新的数字时，当前帧被标记为脏(dirty)，
    ///这会导致widget的build()方法再次被调用，
    ///而在build()中，改变Image的宽高，因为它的高度和宽度现在使用的是animation.value ，所以就会逐渐放大。
    ///值得注意的是动画完成时要释放控制器(调用dispose()方法)以防止内存泄漏。

    //启动动画(正向执行)
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Column(
      children: [
        TextButton(
          child: Text("开启动画"),
          onPressed: () {
            tween.begin = 0.0;
            tween.end = 300.0;
            if (controller.status == AnimationStatus.completed) {
              controller.reverse();
            } else {
              controller.forward();
            }
          },
        ),
        Image.network(
          netWorkImageUrl,
          width: animation.value,
          height: animation.value,
        ),
      ],
    ));
  }

  dispose() {
    //路由销毁时需要释放动画资源
    controller.dispose();
    super.dispose();
  }
}

class CustomHeroAnimation extends StatefulWidget {
  const CustomHeroAnimation({Key? key}) : super(key: key);

  @override
  _CustomHeroAnimationState createState() => _CustomHeroAnimationState();
}

class _CustomHeroAnimationState extends State<CustomHeroAnimation>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  bool _animating = false;
  AnimationStatus? _lastAnimationStatus;
  late Animation _animation;

  //两个组件在Stack中的rect
  Rect? child1Rect;
  Rect? child2Rect;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: Duration(milliseconds: 200));
    //应用curve
    _animation = CurvedAnimation(
      parent: _controller,
      curve: Curves.easeIn,
    );

    _animation.addListener(() {
      if (_controller.isCompleted || _controller.isDismissed) {
        if (_animating) {
          setState(() {
            _animating = false;
          });
        }
      } else {
        _lastAnimationStatus = _controller.status;
      }
    });
    //下面注释的这一段和上面是一样的效果
    // _controller.addListener(() {
    //   if (_controller.isCompleted || _controller.isDismissed) {
    //     if (_animating) {
    //       setState(() {
    //         _animating = false;
    //       });
    //     }
    //   } else {
    //     _lastAnimationStatus = _controller.status;
    //   }
    // });
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    //小头像
    final Widget child1 = wChild1();
    //大头像
    final Widget child2 = wChild2();

    //是否展示小头像；只有在动画执行时、初始状态或者刚从大图变为小图时才应该显示小头像
    bool showChild1 =
        !_animating && _lastAnimationStatus != AnimationStatus.forward;

    // 执行动画时的目标组件；如果是从小图变为大图，则目标组件是大图；反之则是小图
    Widget targetWidget;
    if (showChild1 || _controller.status == AnimationStatus.reverse) {
      targetWidget = child1;
    } else {
      targetWidget = child2;
    }

    return LayoutBuilder(builder: (context, constraints) {
      return SizedBox(
        //我们让Stack 填满屏幕剩余空间
        width: constraints.maxWidth,
        height: constraints.maxHeight,
        child: Stack(
          alignment: AlignmentDirectional.topCenter,
          children: [
            if (showChild1)
              AfterLayout(
                //获取小图在Stack中占用的Rect信息
                callback: (value) => child1Rect = _getRect(value),
                child: child1,
              ),
            if (!showChild1)
              AnimatedBuilder(
                animation: _animation,
                builder: (context, child) {
                  //求出 rect 插值
                  final rect = Rect.lerp(
                    child1Rect,
                    child2Rect,
                    _animation.value,
                  );
                  // 通过 Positioned 设置组件大小和位置
                  return Positioned.fromRect(rect: rect!, child: child!);
                },
                child: targetWidget,
              ),
            // 用于测量 child2 的大小，设置为全透明并且不能响应事件
            IgnorePointer(
              child: Center(
                child: Opacity(
                  opacity: 1,
                  child: AfterLayout(
                    //获取大图在Stack中占用的Rect信息
                    callback: (value) => {child2Rect = _getRect(value)},
                    child: child2,
                  ),
                ),
              ),
            ),
          ],
        ),
      );
    });
  }

  Widget wChild1() {
    //点击后执行正向动画
    return GestureDetector(
      onTap: () {
        print("缩小的按钮");
        setState(() {
          _animating = true;
          _controller.forward();
        });
      },
      child: SizedBox(
        width: 100,
        child: ClipOval(
            child: Image.network(
          netWorkImageUrl,
        )),
      ),
    );
  }

  Widget wChild2() {
    // 点击后执行反向动画
    return GestureDetector(
      onTap: () {
        print("放大的按钮");
        setState(() {
          _animating = true;
          _controller.reverse();
        });
      },
      child: Image.network(
        netWorkImageUrl,
        width: 400,
      ),
    );
  }

  Rect _getRect(RenderAfterLayout renderAfterLayout) {
    //我们需要获取的是AfterLayout子组件相对于Stack的Rect
    return renderAfterLayout.localToGlobal(
          Offset.zero,
          //找到Stack对应的 RenderObject 对象
          ancestor: context.findRenderObject(),
        ) &
        renderAfterLayout.size;
  }
}

class HeroAnimationRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Material(
        child: Container(
      alignment: Alignment.topCenter,
      child: Column(
        children: <Widget>[
          InkWell(
            child: Hero(
              tag: "tgwavatar", //唯一标记，前后两个路由页Hero的tag必须相同
              child: ClipOval(
                child: Image.network(
                  netWorkImageUrl,
                  width: 50,
                ),
              ),
            ),
            onTap: () {
              //打开B路由
              Navigator.push(context, PageRouteBuilder(
                pageBuilder: (
                  BuildContext context,
                  animation,
                  secondaryAnimation,
                ) {
                  return FadeTransition(
                    opacity: animation,
                    child: Scaffold(
                      appBar: AppBar(
                        title: Text("原图"),
                      ),
                      body: HeroAnimationRouteB(),
                    ),
                  );
                },
              ));
            },
          ),
          Padding(
            padding: const EdgeInsets.only(top: 8.0),
            child: Text("点击头像"),
          )
        ],
      ),
    ));
  }
}

class HeroAnimationRouteB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Hero(
        tag: "tgwavatar", //唯一标记，前后两个路由页Hero的tag必须相同
        child: Image.network(
          netWorkImageUrl,
        ),
      ),
    );
  }
}
